package com.qls.redis;

import com.google.gson.Gson;
import com.qls.core.dto.HtDailyRoom;
import com.qls.core.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * redisTemplate封装
 *
 * @author dy
 */
@Component
public class RedisUtil {

    /**
     * 默认到期
     */
    private final static long DEFAULT_EXPIRE = 60 * 60 * 24;
    /**
     * 没有到期
     */
    private final static long NOT_EXPIRE = -1;
    /**
     * gson
     */
    private final static Gson gson = new Gson();
    /**
     * 复述,模板
     */
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 值操作
     */
    @Autowired
    private ValueOperations<String, String> valueOperations;
    /**
     * 散列操作
     */
    @Autowired
    private HashOperations<String, String, Object> hashOperations;
    /**
     * 列表操作
     */
    @Autowired
    private ListOperations<String, Object> listOperations;
    /**
     * 集合操作
     */
    @Autowired
    private SetOperations<String, Object> setOperations;
    /**
     * z集合操作
     */
    @Autowired
    private ZSetOperations<String, Object> zSetOperations;

    public void hashSet(String h, String hk, Object value) {
        hashSet(h, hk, value, NOT_EXPIRE);
    }

    public void hashSet(String h, String hk, Object value, long expire) {
        hashOperations.put(h, hk, value);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(h, expire, TimeUnit.SECONDS);
        }
    }

    public void hashSetAll(String h, Map<? extends String, ?> map) {
        hashSetAll(h, map, NOT_EXPIRE);
    }

    public void hashSetAll(String h, Map<? extends String, ?> map, long expire) {
        hashOperations.putAll(h, map);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(h, expire, TimeUnit.DAYS);
        }
    }

    public Object hashGet(String h, String hk) {
        return hashOperations.get(h, hk);
    }

    public Long hashDel(String h, String... hks) {
        return hashOperations.delete(h, hks);
    }


    public List<Object> hashGetAll(String h, List<String> fields) {
        return hashOperations.multiGet(h, fields);
    }

    public void set(String key, Object value, long expire) {
        valueOperations.set(key, toJson(value));
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }


    public void set(String key, Object value) {
        set(key, value, DEFAULT_EXPIRE);
    }

    /**
     * 集合添加数据
     *
     * @param k
     * @param values
     * @return
     */
    public Long addSet(String k, Object... values) {
        return redisTemplate.opsForSet().add(k, values);
    }

    /**
     * 获取集合的所有数据
     *
     * @param k
     * @return
     */
    public <T> T getSet(String k, Class<T> clazz) {
        return (T) redisTemplate.opsForSet().members(k);
    }

    /**
     * 集合删除数据
     *
     * @param k
     * @param values
     * @return
     */
    public Long remove(String k, Object... values) {
        return redisTemplate.opsForSet().remove(k, values);
    }

    /**
     * 判断是否存在集合中
     *
     * @param k
     * @param value
     * @return
     */
    public boolean exist(String k, Object value) {
        return redisTemplate.opsForSet().isMember(k, value);
    }

    /**
     * 判断是否在hash的filed中
     *
     * @param k
     * @param value
     * @return
     */
    public boolean hashExistFiled(String k, Object value) {
        return hashOperations.hasKey(k, value);
    }

    /**
     * 求差集
     *
     * @param
     * @param k
     * @return
     */
    public Set<Object> difference(String k, String otherK) {
        return redisTemplate.opsForSet().difference(k, otherK);
    }

    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return setOperations.add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    public <T> T get(String key, Class<T> clazz, long expire) {
        String value = valueOperations.get(key);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
        return value == null ? null : fromJson(value, clazz);
    }

    public <T> T get(String key, Class<T> clazz) {
        return get(key, clazz, NOT_EXPIRE);
    }

    public String get(String key, long expire) {
        String value = valueOperations.get(key);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
        return value;
    }

    public String get(String key) {
        return get(key, NOT_EXPIRE);
    }

    public void delete(String key) {
        redisTemplate.delete(key);
    }

    /**
     * Object转成JSON数据
     */
    private String toJson(Object object) {
        if (object instanceof Integer || object instanceof Long || object instanceof Float ||
                object instanceof Double || object instanceof Boolean || object instanceof String) {
            return String.valueOf(object);
        }
        return gson.toJson(object);
    }

    /**
     * JSON数据，转成Object
     */
    private <T> T fromJson(String json, Class<T> clazz) {
        return gson.fromJson(json, clazz);
    }


    /**
     * 批量缓存价态
     *
     * @param htDailyrooms List<HtDailyroom>
     */
    public List<String> saveOrUpdateBatchRates(List<HtDailyRoom> htDailyrooms) {
        List<String> dateList = new ArrayList<>();
        redisTemplate.executePipelined(new RedisCallback<List>() {
            @Override
            public List doInRedis(RedisConnection redisConnection) throws DataAccessException {
                for (HtDailyRoom r : htDailyrooms) {
                    String date = r.getDate();
                    dateList.add(date);
                    byte[] key = ("r:" + r.getRpCode() + ":" + date.substring(date.length() - 5).replace("-", "")).getBytes();
                    // k存活时间增加一小时
                    long diff = DateUtils.suDates(DateUtils.stringToDate(date, DateUtils.DATE_PATTERN), new Date());
                    if (diff < 0) {
                        diff = 0;
                    }
                    long expire = diff + 86400L + 3600L;
                    Map<byte[], byte[]> map = new HashMap<>();
                    Integer store = r.getSaleNum();
                    Integer price = r.getPrice();
                    Integer status = r.getStatus();
                    Integer subPrice = r.getSubPrice();
                    if (store != null) {
                        map.put("n".getBytes(), String.valueOf(store).getBytes());
                    }
                    if (price != null) {
                        map.put("p".getBytes(), String.valueOf(price).getBytes());
                    }
                    if (status != null) {
                        map.put("s".getBytes(), String.valueOf(status).getBytes());
                    }
                    if (subPrice != null) {
                        map.put("b".getBytes(), String.valueOf(subPrice).getBytes());
                    }
                    map.put("d".getBytes(), date.replaceAll("-", "").getBytes());
                    redisConnection.hMSet(key, map);
                    redisConnection.expire(key, expire);
                }
                return null;
            }
        });
        return dateList;
    }


    public List<HtDailyRoom> getRatesBatch(List<String> dateList, String rpCode) {
        List<Object> objects = (List<Object>) redisTemplate.executePipelined(new RedisCallback<List<Object>>() {
            @Override
            public List<Object> doInRedis(RedisConnection redisConnection) throws DataAccessException {

                for (String date : dateList) {
                    String key = "r:" + rpCode + ":" + date.substring(date.length() - 5).replace("-", "");
                    redisConnection.hMGet(key.getBytes(), "p".getBytes(), "n".getBytes(), "s".getBytes(), "b".getBytes(), "d".getBytes());
                }
                return null;
            }
        });
        List<HtDailyRoom> htDailyrooms = new ArrayList<>();
        int i = 0;
        for (Object o : objects) {
            List<Integer> list = (List<Integer>) o;
            Integer price = list.get(0);
            Integer num = list.get(1);
            Integer status = list.get(2);
            Integer subPrice = list.get(3);
            Integer date = list.get(4);
            if (Objects.isNull(price)) {
                continue;
            }
            HtDailyRoom htDailyroom = new HtDailyRoom();
            htDailyroom.setSaleNum(num == null ? 0 : num);
            htDailyroom.setPrice(price);
            htDailyroom.setStatus(status == null ? 0 : status);
            htDailyroom.setSubPrice(subPrice);
            htDailyroom.setDate(DateUtils.dateChange(date.toString()));
            htDailyroom.setRpCode(rpCode);
            htDailyrooms.add(htDailyroom);
            i++;
        }
        return htDailyrooms;
    }

    public Long hashDel(String h, String hks) {
        return hashOperations.delete(h, hks);
    }

    public Object hashGetObject(String h, String hk) {
        return hashOperations.get(h, hk);
    }

}

